/*
 * $Id: Main.cc,v 1.5 2006-02-06 14:49:54 bacon Exp $
 */

#include "Globals.h"
#include "ShellApp.h"
#include <xp/bas/string.h>
#include <xp/bas/locale.h>
#include <xp/bas/memory.h>
#include <xp/bas/stdcli.h>

#if defined(DEBUG) && defined(__linux)
#include <mcheck.h>
#endif

static xp_cli_t* parse_cli (int argc, xp_char_t* argv[]);
static void set_ini_path (const xp_char_t* path);
static void set_log_path (const xp_char_t* path);
static int __xp_main (int argc, xp_char_t* argv[]);

extern "C" { int xp_main (int argc, xp_char_t* argv[]); };


int xp_main (int argc, xp_char_t* argv[])
{
	int n;

#if defined(DEBUG) && defined(__linux)
	mtrace ();
#endif

	if (xp_log_open (&app_log,
		APP_NAME, XP_LOG_CONSOLE | XP_LOG_DEBUG) == XP_NULL) {
		xp_fprintf (xp_stderr, XP_TEXT("cannot open log. aborting"));
		n = -1;
	}
	else {
		n = __xp_main (argc, argv);
		xp_log_close (&app_log);
	}

#if defined(DEBUG) && defined(__linux)
	muntrace ();
#endif
	return n;
}

static int __xp_main (int argc, xp_char_t* argv[])
{
	xp_cli_t* cli;

	/* initialization */
	if (xp_setlocale () == -1) {
		XP_LOG0 (&app_log, XP_NULL,
			XP_LOG_CRITICAL, XP_TEXT("cannot set locale"));
		return -1;
	}

	if (app_path.setToSelf (argv[0]) == -1) {
		XP_LOG1 (&app_log, XP_NULL, XP_LOG_CRITICAL,
			XP_TEXT("cannot get path for %s. aborting"), argv[0]);
		return -1;
	}

	/* parse command line */
	if ((cli = parse_cli (argc, argv)) == XP_NULL) return -1;
	if (xp_getncliparams(cli) > 0) {
		XP_LOG1 (&app_log, XP_NULL, XP_LOG_CRITICAL,
			XP_TEXT("<usage> %s [--foreground] [--ini_file=path] [--log_file=path]"), cli->verb);
		XP_LOG0 (&app_log, XP_NULL, XP_LOG_CRITICAL,
			XP_TEXT("<error> redundant cli parameters"));
		return -1;
	}

	set_ini_path (xp_getclioptval(cli, XP_TEXT("ini_file")));
	set_log_path (xp_getclioptval(cli, XP_TEXT("log_file")));
	if (xp_getclioptval(cli, XP_TEXT("foreground")) != XP_NULL) {
		app_mode = APP_MODE_FOREGROUND;
	}
	xp_clearcli (cli);

	/* begin main logic */
	int ret_code;
	try {
		ShellApp app;

		int err_code;
		if ((!(app_mode & APP_MODE_FOREGROUND) && app.start(&err_code) == -1) ||
		    ((app_mode & APP_MODE_FOREGROUND) && app.startAsNonDaemon(&err_code) == -1)) {
			XP_LOG1 (&app_log, XP_NULL, XP_LOG_CRITICAL,
				XP_TEXT("application startup failure, aborting - %d"),
				err_code);
			ret_code = -1;
		}
		else ret_code = app.returnCode ();
	}
	catch (Exception& ex) {
		XP_LOG1 (&app_log, XP_NULL, XP_LOG_CRITICAL,
			XP_TEXT("application execption caught, aborting - %s"), 
			XPP_EXCEPTION_MSG(ex));
		ret_code = -1;
	}
	catch (...) {
		XP_LOG0 (&app_log, XP_NULL, XP_LOG_CRITICAL,
			XP_TEXT("unknown application execption caught, aborting"));
		ret_code = -1;
	}

	return ret_code;
}

static int handle_cli_error (
	const xp_cli_t* cli, int code, 
	const xp_char_t* name, const xp_char_t* value)
{

	XP_LOG1 (&app_log, XP_NULL, XP_LOG_CRITICAL,
		XP_TEXT("<usage> %s [--foreground] [--ini_file=path] [--log_file=path]"), cli->verb);

	if (code == XP_CLI_ERROR_INVALID_OPTNAME) {
		XP_LOG1 (&app_log, XP_NULL, XP_LOG_CRITICAL, 
			XP_TEXT("<error> unknown option - %s"), name);
	}
	else if (code == XP_CLI_ERROR_MISSING_OPTNAME) {
		XP_LOG1 (&app_log, XP_NULL, XP_LOG_CRITICAL, 
			XP_TEXT("<error> missing option - %s"), name);
	}
	else if (code == XP_CLI_ERROR_REDUNDANT_OPTVAL) {
		XP_LOG2 (&app_log, XP_NULL, XP_LOG_CRITICAL, 
			XP_TEXT("<error> redundant value %s for %s"), value, name);
	}
	else if (code == XP_CLI_ERROR_MISSING_OPTVAL) {
		XP_LOG1 (&app_log, XP_NULL, XP_LOG_CRITICAL, 
			XP_TEXT("<error> missing value for %s"), name);
	}
	else if (code == XP_CLI_ERROR_MEMORY) {
		XP_LOG1 (&app_log, XP_NULL, XP_LOG_CRITICAL, 
			XP_TEXT("<error> memory error in processing %s"), name);
	}
	else {
		XP_LOG1 (&app_log, XP_NULL, XP_LOG_CRITICAL, 
			XP_TEXT("<error> unknown cli error - %d"), code);
	}

	return -1;
}

static xp_cli_t* parse_cli (int argc, xp_char_t* argv[])
{
	static const xp_char_t* optsta[] = 
	{
		XP_TEXT("--"), XP_NULL
	};

	static xp_cliopt_t opts[] = 
	{
		{ XP_TEXT("foreground"), 0 },
		{ XP_TEXT("ini_file"), XP_CLI_OPTVAL },
		{ XP_TEXT("log_file"), XP_CLI_OPTVAL },
		{ XP_NULL, 0 }
	};

	static xp_cli_t cli = 
	{
		handle_cli_error,
		optsta,
		XP_TEXT("="),
		opts
	};

	if (xp_parsecli (argc, argv, &cli) == -1) return XP_NULL;
	return &cli;
}


void set_ini_path (const xp_char_t* path)
{
	xp_char_t pbuf[XP_PATH_MAX + 1];
	
	if (path == XP_NULL) {
		xp_strxapp (
			pbuf, xp_countof(pbuf), app_path.baseDir(), 
			XP_TEXT("/"), APP_INI_FILE, XP_NULL);
	}
	else xp_strxcpy (pbuf, xp_countof(pbuf), path);

	app_env_path.setName (pbuf);
}

void set_log_path (const xp_char_t* path)
{
	xp_char_t pbuf[XP_PATH_MAX + 1];

	if (path == XP_NULL) {
		xp_strxapp (
			pbuf, xp_countof(pbuf), app_path.baseDir(), 
			XP_TEXT("/"), APP_LOG_FILE, XP_NULL);
		xp_log_settargetfile (&app_log, pbuf);
	}
	else xp_log_settargetfile (&app_log, path);
}
